package cn.com.enersun.iec61850.web.controller;

import cn.com.enersun.iec61850.integratedDataProcessing.ClientDataProcessing;
import cn.com.enersun.iec61850.integratedDataProcessing.IntegratedDataProcessing;
import cn.com.enersun.iec61850.web.domain.ConnectModelByDiscover;
import cn.com.enersun.iec61850.web.domain.ConnectModelByScl;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.openmuc.openiec61850.ClientAssociation;
import org.openmuc.openiec61850.ClientSap;
import org.openmuc.openiec61850.Fc;
import org.openmuc.openiec61850.FcModelNode;
import org.slf4j.LoggerFactory;
import cn.com.enersun.iec61850.sclparse.ScdParse;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.lang.reflect.Method;
import java.net.InetAddress;
import javax.servlet.http.HttpServletRequest;
import java.net.UnknownHostException;
import java.util.*;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

/**
 * Created by YYC on 2017/5/31.
 */
@RestController
@RequestMapping("/iec61850")
public class ServerModelController {
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ClientDataProcessing.class);
    private static ObjectMapper mapper = new ObjectMapper();

    // 对象转 Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map
    private Map<String, Object> transObjectToMap(Object obj) {

        if(obj == null){
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);

                    map.put(key, value);
                }

            }
        } catch (Exception e) {
            System.out.println("transBeanToMap Error " + e);
        }

        return map;
    }

    @RequestMapping(value = "/importSCL", method = {RequestMethod.POST })
    Map<String, Object> importSCL(@RequestBody List<ConnectModelByScl> connectModelByScls) {
        Map<String, Object> response = new HashMap<String, Object>();

        if((connectModelByScls == null) || (connectModelByScls.isEmpty())) {
            response.put("success", false);
            response.put("msg", "Json数据解析错误");
            return response;
        }

        List<ConnectModelByScl> connectModelByScls1 = new ArrayList<ConnectModelByScl>();
        for (ConnectModelByScl connectModelByScl : connectModelByScls) {
            try {
                //建立连接
                IntegratedDataProcessing.clientDataProcessing.addClientAssociation(
                        InetAddress.getByName(connectModelByScl.getIp()),
                        Integer.parseInt(connectModelByScl.getPort()));
                //取得数据模型
//                IntegratedDataProcessing.clientDataProcessing.retrieveServerModelByScl(
//                        InetAddress.getByName(connectModelByScl.getIp()),
//                        connectModelByScl.getPath());
                logger.info("添加" + connectModelByScl.getIp() + ":" + connectModelByScl.getPort() + "在线监测设备!");
                connectModelByScls1.add(connectModelByScl);
            } catch (Exception ex) {
                continue;
            }
        }
        if (connectModelByScls1.size() > 0) {
            response.put("success", true);
            List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
            for (ConnectModelByScl connectModelByScl : connectModelByScls) {
                Map<String, Object> subData = this.transObjectToMap(connectModelByScl);
                subData.put("online", true);
                data.add(subData);
            }
            response.put("data", data);
            return response;
        } else {
            response.put("success", false);
            response.put("msg", "错误添加在线监测设备");
        }
        return response;
    }

    @RequestMapping(value = "/discoverIED")
    Map<String, Object> discoverIED(ConnectModelByDiscover connectModelByDiscover) {
        Map<String, Object> response = new HashMap<String, Object>();
        //Map<String, Object> data = new HashMap<String, Object>();

        try{
            //建立连接
            IntegratedDataProcessing.clientDataProcessing.addClientAssociation(
                    InetAddress.getByName(connectModelByDiscover.getIp()),
                    Integer.parseInt(connectModelByDiscover.getPort()));
            //取得数据模型
            IntegratedDataProcessing.clientDataProcessing.retrieveServerModelByNet(
                    InetAddress.getByName(connectModelByDiscover.getIp()));
            logger.info("添加" + connectModelByDiscover.getIp() + ":" + connectModelByDiscover.getPort() + "在线监测设备!");
        }catch (Exception ex) {
            ex.printStackTrace();
            response.put("success", false);
            response.put("msg", ex.getMessage());
            return response;
        }
        response.put("success", true);
        Map<String, Object> data = this.transObjectToMap(connectModelByDiscover);
        data.put("online", true);
        response.put("data", data);
        return response;
    }

    @RequestMapping(value = "/onlineIED")
    Map<String, Object> onlineIED(String ip, String port, boolean online) {
        Map<String, Object> response = new HashMap<String, Object>();
        Map<String, Object> data = new HashMap<String, Object>();

        if(online) {
            ClientAssociation clientAssociation = IntegratedDataProcessing.clientDataProcessing.getClientAssociation(ip);
            if(!clientAssociation.isClosed()) {
                clientAssociation.disconnect();
                IntegratedDataProcessing.clientDataProcessing.getClientAssociations().remove(ip);
            }
            IntegratedDataProcessing.clientDataProcessing.getIntegratedDataProcessing().updateDeviceStatus(ip, !online);
            data.put("ip", ip);
            data.put("port", port);
            data.put("online", !clientAssociation.isClosed());
        }else {
            try {
                IntegratedDataProcessing.clientDataProcessing.getClientAssociations().put(ip,  new ClientSap().associate(
                        InetAddress.getByName(ip), Integer.parseInt(port),
                        null));
                IntegratedDataProcessing.clientDataProcessing.getIntegratedDataProcessing().updateDeviceStatus(ip, !online);
                data.put("ip", ip);
                data.put("port", port);
                data.put("online", !IntegratedDataProcessing.clientDataProcessing.getClientAssociation(ip).isClosed());
            } catch (UnknownHostException e) {
                e.printStackTrace();
                response.put("success", false);
                response.put("msg", "连接失败，未识别主机!");
                return response;
            } catch (IOException e) {
                e.printStackTrace();
                response.put("success", false);
                response.put("msg", "连接失败，设备IO口读取错误!");
                return response;
            }
        }

        response.put("success", true);
        response.put("data", data);
        return response;
    }



    @RequestMapping(value = "/closeIED")
    Map<String, Object> closeIED(String ip, Boolean online) {
        Map<String, Object> response = new HashMap<String, Object>();
        Map<String, Object> data = new HashMap<String, Object>();
        try{
            IntegratedDataProcessing.clientDataProcessing.closedClientAssociation(ip);
            IntegratedDataProcessing.clientServerModels.remove(ip);
            IntegratedDataProcessing.clientDataProcessing.getClientServerModels().remove(ip);

        }catch (Exception ex) {
            response.put("success", false);
            response.put("msg", "在线检测设备关闭错误!");
            return response;
        }
        data.put("ip", ip);
        response.put("success", true);
        response.put("data", data);
        return response;
    }

    @RequestMapping(value = "/setIedProperties")
    Map<String, Object> setIedProperties(String name, String ip, String proxyIp, String proxyPort, String online) {
        Map<String, Object> response = new HashMap<String, Object>();

        ClientAssociation clientAssociation = IntegratedDataProcessing.clientDataProcessing.getClientAssociation(ip);
        if(clientAssociation == null){
            response.put("success", false);
            response.put("msg", "未查找到在线监测设备!");
            return response;
        }
        List<String> data = new ArrayList<String>();
        data.add(ip);
        data.add(name);
        response.put("success", true);
        response.put("data", data);
        return response;
    }

    @RequestMapping(value = "/readIedBda")
    Map<String, Object> readIedBda(String ip, String nodeId) {
        Map<String, Object> response = new HashMap<String, Object>();

        FcModelNode fcdo = (FcModelNode) IntegratedDataProcessing.clientServerModels.get(ip).findModelNode(nodeId, null);
        if (fcdo.getFc() != Fc.CO) {
            try {
                IntegratedDataProcessing.clientDataProcessing.getClientAssociations().get(ip).getDataValues(fcdo);
            }catch (Exception e){
                logger.info(fcdo.toString() + "节点数据获取失败!");
                response.put("success", false);
                response.put("msg", fcdo.toString() + "节点数据获取失败!");
                return response;
            }
        }
        List<String> data = new ArrayList<String>();
        data.add(ip);
        data.add(nodeId);
        response.put("success", true);
        response.put("data", data);
        return response;
    }

    @RequestMapping(value = "/readIedAllBda")
    Map<String, Object> readIedAllBda(String ip) {
        Map<String, Object> response = new HashMap<String, Object>();

        try{
            IntegratedDataProcessing.clientDataProcessing.getClientAssociations().get(ip).getAllDataValues();
        }catch (Exception ex){
            logger.error("Error get data values.", ex);
            response.put("success", false);
            response.put("msg", ex.getMessage());
            return response;
        }

        response.put("success", true);
        response.put("data", ip);
        return response;
    }

    @RequestMapping(value = "/writeIedBda")
    Map<String, Object> writeIedBda(String parameter) {
        return null;
    }

    /**
     * 打开scl文件
     * @param request
     * @param file
     * @return
     */
    @RequestMapping(value = "/openSCL")
    public Map<String, Object> openSCL(HttpServletRequest request,
                                       @RequestParam(value = "sclFile", required = true) MultipartFile file) {
        Map<String, Object> result = new HashMap<String, Object>();
        try {
            if (file!=null) {
                //上传文件
                String fileUrl = "upload/scl";

                String appendsPath = request.getSession().getServletContext().getRealPath("/");

                String fileName = file.getOriginalFilename();
                String saveFileName = UUID.randomUUID().toString().replaceAll("-", "")
                        + fileName.substring(fileName.lastIndexOf("."));
                String saveDir = appendsPath+fileUrl;
                File directory = new File(saveDir);
                if (!directory.exists()) {
                    directory.mkdirs();
                }
                FileUtils.cleanDirectory(directory); //清除目录
                fileUrl += "/" +saveFileName;
                String saveFilePath = appendsPath + fileUrl;//保存文件路径
                file.transferTo(new File(saveFilePath));

                //效验文件
//                URL url = ServerModelController.class.getResource("/SCL/SCL.xsd");
//                String xsdPath = url.getPath();
//                if (!ScdParse.validateXMLSchema(xsdPath, saveFilePath)) {
//                    result.put("success", false);
//                    result.put("msg", "文件格式不正确");
//                }

                //转换成icd文件
                String icdFileDirPath = appendsPath + "upload/icd";
                File icdFileDir = new File(icdFileDirPath);
                if (!icdFileDir.exists()) {
                    icdFileDir.mkdirs();
                }
                FileUtils.cleanDirectory(icdFileDir); //清除目录
                List<ConnectModelByScl> icds = ScdParse.transferToIcd(saveFilePath, icdFileDirPath);

                result.put("data", icds);
                result.put("success", true);
            }
        } catch (Exception e) {
            e.printStackTrace();
            result.put("success", false);
            result.put("msg", "上传文件失败");
        }
        return result;
    }
}
